
#include	"SysConfig.h"
//#include	"Define.h"
#include	"Port.h"
#include	"Boot_LC786.h"
#include	"Boot_Util.h"
#include	"Boot_FlashDrv.h"
#include	"Boot_Display.h"
#include	"UserBoot.h"

static union {
	unsigned char   ub[128];
	unsigned short   uw[ (128 / sizeof (unsigned short)) ];
}BOOT_FlashData;

unsigned short usBOOT_FlashData[3];
unsigned char BOOT_FlashDataCnt;
unsigned short usBOOT_HostFirmwareSize;
unsigned short usBOOT_HostFirmwareOffset;


#define	BOOT_FIRM_SEQ_START		0
#define	BOOT_FIRM_SEQ_FORMAT	1
#define	BOOT_FIRM_SEQ_SKIP		2
#define	BOOT_FIRM_SEQ_NUM_DATA	3
#define	BOOT_FIRM_SEQ_ADDRESS	4
#define	BOOT_FIRM_SEQ_DATA		5

unsigned char ucBOOT_FirmFormat;
#define	FIRM_FORMAT_S1	8
#define	FIRM_FORMAT_S2	16

#pragma SECTION program UserBoot_Sector

void BOOT_SetHostFirmwareSize(unsigned short usSize)
{
	usBOOT_HostFirmwareSize = usSize;
}
void BOOT_SetHostFirmwareOffset(unsigned short usSize)
{
	if  (usSize > 127)
	{
		++usBOOT_HostFirmwareOffset;
	}
}

unsigned char BOOT_Char2HEX(unsigned char ucData)
{
	unsigned char ucHex;
	
	if  ((ucData > ('0' - 1)) && (ucData < ('9' + 1)))
	{
		ucHex = ucData - '0';
	}
	else  if  ((ucData > ('a' - 1)) && (ucData < ('z' + 1)))
	{
		ucHex = ucData - 'a' + 0x0A;
	}
	else  if  ((ucData > ('A' - 1)) && (ucData < ('Z' + 1)))
	{
		ucHex = ucData - 'A' + 0x0A;
	}
	else
	{
		// error
	}
	return(	ucHex );
}


void BOOT_FirmwarePercent(void)
{
	unsigned char ucPer;

	ucPer = (usBOOT_HostFirmwareOffset * 10) / (usBOOT_HostFirmwareSize / 10);

	if  (ucPer < 100)
	{
		BOOT_DISP_Update_Percent(ucPer);
	}
}

void BOOT_FirmwareUpdate(void)
{
	unsigned char ucBuf[3];
	unsigned char ucMode = 0;
	unsigned char ucDataNum;
	unsigned long ulFirmAddress = 0;
	unsigned long ulTempAddress = 0;
	unsigned char i;
	unsigned long ucReadCnt;
	
	asm("fclr I");	/* Interrupt disabled */

	BOOT_EraseAllBlock();

	BOOT_FlashDataCnt = 0;
	BOOT_memset(&BOOT_FlashData.ub[0], 0xFF, 128);
	ucReadCnt = 0;

	while(1)
	{
		switch  (ucMode)
		{
			case BOOT_FIRM_SEQ_START:
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				if  (ucBuf[0] == 'S')
				{
					ucMode = BOOT_FIRM_SEQ_FORMAT;
				}
				break;
			case BOOT_FIRM_SEQ_FORMAT:
				BOOT_FirmwarePercent();
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				if  (ucBuf[0] == '1')
				{
					ucMode = BOOT_FIRM_SEQ_NUM_DATA;
					ucBOOT_FirmFormat = FIRM_FORMAT_S1;
				}
				else  if  (ucBuf[0] == '2')
				{
					ucMode = BOOT_FIRM_SEQ_NUM_DATA;
					ucBOOT_FirmFormat = FIRM_FORMAT_S2;
				}
				else  if  (ucBuf[0] == '0')
				{
					// File Start....
					ucMode = BOOT_FIRM_SEQ_SKIP;
				}
				else  if  (ucBuf[0] == '8')
				{					
					if  (BOOT_FlashDataCnt != 0)
					{
						BOOT_FlashWrite((unsigned short far *)ulFirmAddress, &BOOT_FlashData.uw[0], BOOT_FlashDataCnt);
					}
					usBOOT_FlashData[0] = 0x6576;
					usBOOT_FlashData[1] = 0x3072;
					usBOOT_FlashData[2] = 0x3130;
					BOOT_FlashWrite((unsigned short far *)0xEFFF0, &usBOOT_FlashData[0], 6);
					#ifdef  M16C_30PG
					BOOT_FlashWrite((unsigned short far *)0xC0000, &usBOOT_FlashData[0], 6);
					#else
					BOOT_FlashWrite((unsigned short far *)0x80000, &usBOOT_FlashData[0], 6);
					#endif
					BOOT_DISP_Update_Complete();
					BOOT_Timer1msec(3000);
				#ifdef  ST7565P
					PO_ST7565_RST = 0;
				#endif
				#ifdef  PT6524
					PO_PT6524_RST = 0;
					BOOT_Timer1msec(1000);
				#endif
				#ifdef  M16C_64G
					wdtr = 0xFF;
					prcr = 0x30;
					pm12 = 1;
					prcr = 0x00;
					wdts = 1;
				#endif
				#ifdef  M16C_30PG
					prc1 = 1; /* Write enabled */ 
					pm12 = 1; /* Watchdog timer function is selected to "Watchdog timer reset" */ 
					prc1 = 0; /* Write protected */ 
		 			wdts = 1; /* Set watchdog timer start register */
				#endif
					while(1)
					{
					}
				}
				else
				{
					ucMode = BOOT_FIRM_SEQ_SKIP;
				}
				break;
			case BOOT_FIRM_SEQ_NUM_DATA:				
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				ucDataNum = 0;
				ucDataNum = BOOT_Char2HEX(ucBuf[0]);
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				ucDataNum = (ucDataNum << 4) & 0xF0;
				ucDataNum = ucDataNum | BOOT_Char2HEX(ucBuf[0]);

				ucReadCnt = 0;
				ucMode = BOOT_FIRM_SEQ_ADDRESS;
				break;
			case BOOT_FIRM_SEQ_ADDRESS:
				ulTempAddress = 0;
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				ulTempAddress = BOOT_Char2HEX(ucBuf[0]);

				for(i = 0; i < 5; ++i)
				{
					ulTempAddress = (ulTempAddress << 4) & 0xFFFFFFF0;
					ulTempAddress = ulTempAddress | BOOT_Char2HEX(BOOT_LC786XXX_GetData(&ucReadCnt));
				}
				if  (ulFirmAddress == 0)
				{
					ulFirmAddress = ulTempAddress;
				}
				if  ((ulTempAddress & 0xF0000) == 0xF0000)
				{
					ucMode = BOOT_FIRM_SEQ_SKIP;
				}
				else
				{
					if  (ulTempAddress == (ulFirmAddress + BOOT_FlashDataCnt))
					{
					}
					else
					{
					#if  1
						while(1)
						{
							if  (++BOOT_FlashDataCnt > 127)
							{
								BOOT_FlashWrite((unsigned short far *)ulFirmAddress, &BOOT_FlashData.uw[0], BOOT_FlashDataCnt);
								BOOT_memset(&BOOT_FlashData.ub[0], 0xFF, 128);
								ulFirmAddress = ulFirmAddress + 128;
								BOOT_FlashDataCnt = 0;
							}
							if  (ulTempAddress == (ulFirmAddress + BOOT_FlashDataCnt))
							{
								break;
							}
						}
					#else
						if  (BOOT_FlashDataCnt != 0)
						{	
							if  ((BOOT_FlashDataCnt % 2) != 0)
							{
								++BOOT_FlashDataCnt;
							}
							BOOT_FlashWrite((unsigned short far *)ulFirmAddress, &BOOT_FlashData.uw[0], BOOT_FlashDataCnt);
						
							BOOT_memset(&BOOT_FlashData.ub[0], 0xFF, 128);
						}
						ulFirmAddress = ulTempAddress;
						BOOT_FlashDataCnt = 0;
					#endif
					}
					ucMode = BOOT_FIRM_SEQ_DATA;
				}
				break;
			case BOOT_FIRM_SEQ_DATA:
				while(1)
				{
					ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
					BOOT_FlashData.ub[BOOT_FlashDataCnt] = BOOT_Char2HEX(ucBuf[0]);
					ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
					BOOT_FlashData.ub[BOOT_FlashDataCnt] = ((BOOT_FlashData.ub[BOOT_FlashDataCnt] << 4) & 0xF0) | BOOT_Char2HEX(ucBuf[0]);
					++BOOT_FlashDataCnt;
					if  (BOOT_FlashDataCnt > 127)
					{
						BOOT_FlashWrite((unsigned short far *)ulFirmAddress, &BOOT_FlashData.uw[0], BOOT_FlashDataCnt);
						ulFirmAddress = ulFirmAddress + 128;
						BOOT_memset(&BOOT_FlashData.ub[0], 0xFF, 128);
						BOOT_FlashDataCnt = 0;
					}
					if  (ucReadCnt == ((ucDataNum * 2) - 2))
					{
						ucMode = BOOT_FIRM_SEQ_START;
						break;
					}
				}
				break;
			case BOOT_FIRM_SEQ_SKIP:
				ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				while(1)
				{
					if  (ucBuf[0] == 0x0D)
					{
						ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
						if  (ucBuf[0] == 0x0A)
						{
							ucMode = BOOT_FIRM_SEQ_START;
							break;
						}
					}
					ucBuf[0] = BOOT_LC786XXX_GetData(&ucReadCnt);
				}
				break;
		}
	}
}

/*////////////////////////////////////////////////////////////////////////////////
Title : void BOOT_Update_Start(unsigned char ucMode)
ucMode
	-. 0 : Host
	-. 1 : Bluetooth
	-. 2 : CD/USB
	-. 3 : Host form Boot
////////////////////////////////////////////////////////////////////////////////*/
#pragma SECTION program Boot_Init_SEC

void BOOT_UpgradeInit(void)
{
	//INIT
	unsigned short i;
#ifdef  M16C_64G
	prcr = 0x03;	// CM0,CM1,CM2,PLC0,PCLKR,FRA0 register protect off
					// PM0,PM1,PM2,TB2SC,INVC0,INVC1 register protect off
	pm0 = 0x00; 	// Processor mode: Single-chip mode */ -> All pins are I/O ports or peripheral function I/O pins
	pm1 = 0x08; 	// Watchdog timer function: Watchdog timer interrupt
					// Internal reserved area: The entire area usable
					// Wait: No wait state
	cm2 = 0x00; 	// System clock select: Main clock

	cm1 = 0x00		// Main clock division select: No division mode
		| 0x00		// XIN-OUT drive capacity : Low
		| 0x10		// 125 kHz on-chip oscillator stop : Off
		| 0x00; 	// etc...
	cm0 = 0x18; 	// Main clock division select: CM16 and CM17 enabled
	cm07 = 0;
	pm20  = 1;		// SFR 1wait when PLL on
	plc0  = 0x23;	// PLL clock Multiply by 4
					//PLL multiplying factor select: Multiply by 8
					// Reference frequency counter: Divide by 2
	plc07 = 1;					 // PLL operation enable: PLL ON
	for (i = 0; i < 20000; i++); // Wait until the PLL clock becomes stable (tsu(PLL))
	cm11  = 1;					 // System clock select: PLL clock
	prcr = 0x00;

#endif
#ifdef M16C_30PG

	prcr = 0x01;
	pm0 = 0x40;

	cm05 = 0;
	cm07 = 0;
	cm15 = 1;	
	cm03 = 1;
	cm06 = 0;
	cm04 = 1;
	prcr = 0x00;

	//TIME
	/////////////// Main Clock 16MHz ////////////////
	
#endif
	ta0mr = 0x00;
	tck1_ta0mr = 1; 	// f32TIMAB
	tck0_ta0mr = 0;
#ifdef	M16C_64G
	ta0 = 3750 - 1; 
#else
	ta0 = 2500 - 1;// 5msec = 5000usec = (n - 1) * 5usec
						// 5 usec = f(1/32)MHz
#endif	

#if  0
	ta0ic = 2;			// Interrupt level 2
	ir_ta0ic = 0;		// Interrupt not requested

	ta0s = 1;	// Timer A0 count start flag
#if  1
	ta1mr = 0xC0;	// Count Source Select : fc32 ( Sub clock )
	ta1 = 1024 - 1; // (32.768 KHz / 32) = 1.024 KHz = 1024 Hz => (1/1024) sec

	ta1ic = 1;			// Interrupt Level 1
	ir_ta1ic = 1;		// Interrupt not requested
	
	ta1s = 1;	// Timer A1 count start flag
#endif
	ta2mr = 0x37;
	ta2= 33054;  
#endif
	//PORT
#ifdef  M16C_64G

	pd10 = 0x22; // BIN_0010_0110
				// PO_MOTOR : Defulat is Input, share whith LC786XXX
	prcr = 0x04;
	pd9 = 0x7F; // BIN_0111_1111
	pd8 = 0x01; // BIN_0000_0001
	pd7 = 0x7D; // BIN_0111_1101

	pd6 = pd6 & 0xF0;	 
	pd6 = pd6 | 0x0A | 0x01;	// BIN_0000_1010  

	pd5 = pd5 & 0x21;
	pd5 = 0x04; // BIN_0000_0100
	pd4 = 0xBF; // BIN_1110_0100

	pd2 = 0x03; // BIN_0000_0011
	//	pu04 = 1;
	pd1 = 0x9B; // BIN_1000_1011
	pd0 = 0xA0; // BIN_1010_0000

	p10 = 0x00;
	p9 = 0x00;
	p8 = 0x00;
#ifdef  NXP
	p8 = p8 | 0x01;
#endif
	p7 = 0x00;
#ifdef  NXP
	p7 = p7 | 0x40;
#endif

	p6 = p6 & 0xF0;

	p5 = 0x00;
	p4 = 0x00;
	p2 = 0x01;	// Mute On
	p1 = 0x00;
	p0 = 0x00;

	p4 = p4 | 0x10; // EEPROM CS High
	pu11 = 1;	// Pull-Up For eeprom
	PO_SF_WP = 1;
#endif	// Under is MODEL_ARA5040
#ifdef  M16C_30PG
	pd10 = 0x00;
	prcr = 0x04;
	pd9 = 0x0F;
	pd7 = 0x3D; // 0011 1101

	pd5 = pd5 & 0x21;
	pd5 = pd5 | 0x04;

	pd6 = pd6 & 0xF0;	// For E8A
	pd6 = pd6 | 0x0B;	// For E8A
	pd4 = 0xC3; // 0xC3

	pd3 = 0x80;
	pd2 = 0x23;
	//	pu04 = 1;
	pd1 = 0x22; 
	pd0 = 0x20;

#endif
	prc2 = 0;


	//Ser
#ifdef  BLUETOOTH
	u0c1  = 0x00;	
	u0mr = 0x05;	
	u0c0 = 0x10;	/* U1BRG count source: f1SIO */
	u0c1 = 0x00;	/* Data logic: No reverse */
	u0irs = 0;	
	u0rrm = 0;
	clkmd0 = 0;
	rcsp = 0;
	u0brg = 38;
	u0smr  = 0x00;	/* 00h is set the UART1 special mode register */
	u0smr2 = 0x00;	/* 00h is set the UART1 special mode register 2 */
	u0smr3 = 0x00;	/* 00h is set the UART1 special mode register 3 */
	u0smr4 = 0x00;	/* 00h is set the UART1 special mode register 4 */
	s0tic = 0x01;	/* UART1 transmit Interrupt: Level 1 */
	s0ric = 0x02;	/* UART1 receive Interrupt : Level 2 */
	u0c1  = 0x05;
	u0bcnic = 0x02;
#endif


#ifdef  LC786XXX
#ifdef  M16C_64G
	prcr = 0x04;	// Clearing the protect

	s4c = 0x00	// Internal synchronous clock select bit : Selecting f1SIO or f2SIO
		| 0x00	// SOUTi output disable bit : SOUTi output enabled
		| 0x08	// SI/Oi port select bit :SOUTi output, CLKi function serial interface enabled
		| 0x00	// CLK polarity select bit : Transmit data is output at rising edge of transfer clock and receive data is input at falling edge
		| 0x20	// Transfer direction select RW bit : MSB first
		| 0x40	// Synchronous clock RW select bit : Internal clock
		| 0x80; // SOUTi initial value set bit : "H" Output
	s4brg = 60; // BRGi divides the count source by n + 1 where n = set value
	s34c2 = 0x00;	// SOUT3,4 output control bit : High-impedance

	prcr = 0x00;	//Protect on
	s4ic = 0x03;
	ifsr7 = 0;
#endif
#ifdef  M16C_30PG
	u0mr = 0x01;	// Serial I/O mode select bit[0,1,2] : (001) Clock synchronous serial I/O mode
	u0c0 = 0x98;
	u0brg = 20;
	u0c1 = 0x01 | 0x04;
	u0smr2 = 0x00;
	u0smr3 = 0x00;
	u0smr4 = 0x00;
	s0tic = 0x04;
	u0irs = 1;
#endif
#endif

#ifdef ST7565P
	u2mr = 0x01;	// Serial I/O mode select bit[0,1,2] : (001) Clock synchronous serial I/O mode
	u2c0 = 0x90;
	u2brg = 30;
	u2c1 = 0x11;
	u2smr2 = 0x00;
	u2smr3 = 0x00 | 0x02;
	u2smr4 = 0x00;
#endif

#ifdef	PT6524

	u2mr = 0x01;	// Serial I/O mode select bit[0,1,2] : (001) Clock synchronous serial I/O mode
	u2c0 = 0x90;
	u2brg = 100;
	u2c1 = 0x11;
	u2smr2 = 0x00;
	u2smr3 = 0x00 | 0x02;
	u2smr4 = 0x00;
#endif

#ifdef  SERIAL_FLASH
	///////////////////////////// Serial 7 : EEPROM  /////////////////////////////////
	u7mr = 0x01;	// Serial I/O mode select bit[0,1,2] : (001) Clock synchronous serial I/O mode
	u7c0 = 0x90;
	u7brg = 40;//25;//80; 25 ->40 24MHz
	u7c1 = 0x10;//0x10;
	u7smr2 = 0x00;
	u7smr3 = 0x00 | 0x02;
	u7smr4 = 0x00;

#endif

	PO_ACC = 1;
#ifdef  MODEL_AGC5030
	PO_PWR1 = 1;
	PO_PWR2 = 1;
	PO_PWR3 = 1;	
//	PO_BACKLIGHT = 1;	// ????????
#endif
#ifdef  MODEL_AGC505X
	PO_PWR1 = 1;
	PO_PWR2 = 1;
	PO_PWR3 = 1;	
//	PO_BACKLIGHT = 1;	// ????????
#endif

#ifdef  MODEL_ARA5040
	PO_ANT = 1;
	PO_USB_PWR = 1;
#endif 
}
#pragma SECTION program UserBoot_Start

void BOOT_Update_Start(unsigned char ucMode)
{
	PO_MUTE = 1;
	ta0ic = 0;		// Timer A0 interrupt disable
	ta0s = 0;		// Timer A0 count stop
	usBOOT_HostFirmwareSize = 0;
	usBOOT_HostFirmwareOffset = 0;
	BOOT_DisplayInit();
	BOOT_LC786XXX_Init();
	BOOT_LC786ValiableInit();
	BOOT_LC786XXX_USB_Detect(ucMode);
	BOOT_DISP_START_UPDATE();
	BOOT_DISP_InitPercent();
	switch  (ucMode)
	{
		case 0:
		case 3:
			BOOT_FirmwareUpdate();
			break;
	#ifdef  BLUETOOTH
		case 1:
		//	BT_DFU_Main();
			break;
	#endif
		case 2:
			break;
	}
	//LC786XXX_StartInitialize();
	PO_MUTE = 0;
}

